/*
  © 2022 BLACK SESAME TECHNOLOGIES
 All rights reserved.
 (This product is licensed to: [Hanhai-ADSP Autonomous Driving Solution Platform]
 This computer software is protected by copyright law and international treaties.
 Use, reproduction, or distribution of this software is subject to the license agreement between you
 and Black Sesame Technologies. Unauthorized reproduction or distribution of this program, or any
 portion of it, may result in severe civil and criminal penalties and will be prosecuted to the
 maximum extent possible under the law.
*/

#include <thread>
#include <gtest/gtest.h>
#include "dal/domain_participant.h"
#include "dal/publisher.h"
#include "dal/subscriber.h"
#include "dal/topic.h"
#include "dal/participant_monitor.h"
#include "dal_greenstonedds/rtps/GuidUtils.hpp"
#include "dal_greenstonedds/utils/ConfigParse.h"
#include "data_type/HelloWorldTopicDataType.h"

TEST(domain_participant_create_and_delete, test_domain_participant)
{
    dal_ret_t ret;
    dal_domain_participant_listener_callbacks_t callbacks = { };
    dal_domain_participant_listener_t* listener = dal_create_domain_participant_listener(callbacks);

    dal_domain_participant_t* participant =
        dal_create_domain_participant(20, DAL_PARTICIPANT_QOS_DEFAULT, listener, DAL_ANY_STATUS);
    EXPECT_NE(participant->handle_, nullptr);

    ret = dal_delete_domain_participant_listener(listener);
    EXPECT_EQ(ret, DAL_RETCODE_PRECONDITION_NOT_MET);
    ret = dal_delete_domain_participant(participant);
    EXPECT_EQ(ret, DAL_RETCODE_OK);
    ret = dal_delete_domain_participant_listener(listener);
    EXPECT_EQ(ret, DAL_RETCODE_OK);
}

TEST(topic_create_and_delete, test_domain_participant)
{
    dal_ret_t ret;
    dal_domain_participant_listener_callbacks_t participant_callbacks = { };
    dal_domain_participant_listener_t* participant_listener =
        dal_create_domain_participant_listener(participant_callbacks);
    dal_domain_participant_t* participant = dal_create_domain_participant(
        20, DAL_PARTICIPANT_QOS_DEFAULT, participant_listener, DAL_ANY_STATUS);

    HelloWorldTopicDataType* helloType = new HelloWorldTopicDataType();
    EXPECT_NE(helloType, nullptr);
    dal_type_support_t* ts = dal_create_type_support(helloType);
    EXPECT_NE(ts, nullptr);

    std::string type_name = "HelloWorldTopicDataType";
    ret = dal_type_support_register_type(ts, participant, type_name.c_str());
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_topic_listener_callbacks_t topic_callbacks = { };
    dal_topic_listener_t* topic_listener = dal_create_topic_listener(topic_callbacks);
    EXPECT_NE(topic_listener->handle_, nullptr);

    dal_topic_t* topic = dal_domain_participant_create_topic(participant,
                                                             "HelloWorldTopic",
                                                             type_name.c_str(),
                                                             DAL_TOPIC_QOS_DEFAULT,
                                                             topic_listener,
                                                             DAL_ANY_STATUS);

    EXPECT_NE(topic->handle_, nullptr);

    ret = dal_delete_topic_listener(topic_listener);
    EXPECT_EQ(ret, DAL_RETCODE_PRECONDITION_NOT_MET);
    ret = dal_domain_participant_delete_topic(participant, topic);
    EXPECT_EQ(ret, DAL_RETCODE_OK);
    ret = dal_delete_topic_listener(topic_listener);
    EXPECT_EQ(ret, DAL_RETCODE_OK);
    dal_delete_type_support(ts);

    dal_delete_domain_participant(participant);
    dal_delete_domain_participant_listener(participant_listener);
}

void monitor_callback(dal_participant_monitor_info_t* monitor_info, void* data)
{
    (void*)data;
    int i;
    std::string participant_name(
        monitor_info->participant_name.str, 0, monitor_info->participant_name.length);

    switch (monitor_info->status) {
        case DAL_PARTICIPANT_ONLINE:
            std::cout << "[DAL_PARTICIPANT_ONLINE] guid:";
            break;
        case DAL_PARTICIPANT_OFFLINE_NORMALLY:
            std::cout << "[DAL_PARTICIPANT_OFFLINE_NORMALLY] guid:";
            break;
        case DAL_PARTICIPANT_OFFLINE_ABNORMALLY:
            std::cout << "[DAL_PARTICIPANT_OFFLINE_ABNORMALLY] guid: ";
            break;
        default:
            break;
    }
    for (i = 0; i < GUIDPREFIX_SIZE; i++) {
        std::cout << std::hex << std::setfill('0') << std::setw(2)
                  << (int)(monitor_info->guid.guidprefix.value[i]);
    }
    for (i = 0; i < ENTITYID_SIZE; i++) {
        std::cout << std::hex << std::setfill('0') << std::setw(2)
                  << (int)(monitor_info->guid.entity_id.value[i]);
    }

    std::cout << ", participant_name: " << participant_name << std::endl;
}

TEST(participant_monitor, test_domain_participant)
{
    dal_ret_t ret;
    dal_guid_t participant_guid = { };
    dal_guid_t participant_2_guid = { };
    dal_domain_participant_listener_callbacks_t participant_callbacks = { };
    dal_domain_participant_listener_t* participant_listener =
        dal_create_domain_participant_listener(participant_callbacks);
    dal_domain_participant_listener_set_participant_monitor_callback(
        participant_listener, monitor_callback, nullptr);

    dal_domain_participant_t* participant = dal_create_domain_participant(
        20, DAL_PARTICIPANT_QOS_DEFAULT, participant_listener, DAL_ANY_STATUS);
    participant_guid = dal_domain_participant_get_guid(participant);

    dal_domain_participant_t* participant_2 =
        dal_create_domain_participant(20, DAL_PARTICIPANT_QOS_DEFAULT, nullptr, DAL_ANY_STATUS);

    participant_2_guid = dal_domain_participant_get_guid(participant_2);

    std::this_thread::sleep_for(std::chrono::seconds(3));

    EXPECT_EQ(dal_guid_is_on_same_host(&participant_guid, &participant_2_guid), 1);
    EXPECT_EQ(dal_guid_is_on_same_process(&participant_guid, &participant_2_guid), 1);

    EXPECT_EQ(dal_guidprefix_is_same(&participant_guid, &participant_2_guid), 0)
        << "guid1: " << convertDalGuidToString(&participant_guid) << "\n"
        << "guid2: " << convertDalGuidToString(&participant_2_guid);

    ret = dal_delete_domain_participant(participant_2);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    ret = dal_delete_domain_participant(participant);
    EXPECT_EQ(ret, DAL_RETCODE_OK);

    dal_delete_domain_participant_listener(participant_listener);
}